#ifndef __THREADMGR_H__
#define __THREADMGR_H__

#include <pthread.h>
#include <iostream>
#include <vector>
#include <string>
#include "database.h"
#include "threadobj.h"
#include "log.h"
#include <sstream>
#include <cstdlib>
#include "mpi.h"
#include "outstream.h"

using namespace std;

struct ThreadInfo
{
    pthread_cond_t* condi;
    pthread_mutex_t* mute;
};

struct ThreadInfo2
{
  OutStream* theStream;
  ifstream* infile;
  string input1;
  string input2;
  int threadID;
};


class ThreadMgr
{
  public:
    ThreadMgr()
    {

    }

    static void exitThread(int id)
    {
      pthread_mutex_lock(&mutex);
        for(unsigned int i = 0; i < threads.size(); ++i)
        {
            if(*(threads[i].getID()) == id)
                threads.erase(threads.begin() + i);
        }
	pthread_mutex_unlock(&mutex);
    }

    void run(int argc, char* argv[])
    {
        errorLog = Log::getInstance();
	this->argc = argc;
	this->argv = (argv);
        input.push_back("");
        input.push_back("");
        input.push_back("");
        ThreadObj temp;

	stream.init();

        threads.push_back(temp);
        threads[0].setID(threadNum++);
        threads[0].setDescription("Creating and Managing all Threads");
	int something = 0;
        pthread_create(threads[0].getThread(), 
		       NULL, ThreadMgrThread, (void*)&something);
    }

    pthread_cond_t* getCondition()
    {
        return &condition;
    }

    pthread_mutex_t* getMutex()
    {
        return &mutex;
    }

    void setData(vector <string> data)
    {
        input[0] = data[0];
        input[1] = data[1];
        input[2] = data[2];
    }

    static void* kill(void* arg)
    {
      struct ThreadInfo2 info = *(((struct ThreadInfo2*) arg));
      int id = info.threadID;
      string threadID = info.input1;
      errorLog->logMessageCreate(id);
      pthread_mutex_lock(&mutex);
      for(unsigned int i = 0; i < threads.size(); ++i)
        {
	  if(*(threads[i].getID()) == atoi(threadID.c_str()))
	  {
	    pthread_cancel(*(threads[i].getThread()));
	    exitThread(*(threads[i].getID()));
	  }
        }
      pthread_mutex_unlock(&mutex);
      
      exitThread(id);
      errorLog->logMessageExit(id);
      pthread_exit(NULL);
    }
    static void* list(void* arg)
    {
      int id = ((struct ThreadInfo2*) arg)->threadID;
      struct ThreadInfo2* info = (((struct ThreadInfo2*) arg));
      
        errorLog->logMessageCreate(id);
	pthread_mutex_lock(&mutex);
	info->theStream->mutex_lock();
	for(unsigned int i = 0; i < threads.size(); ++i)
        {
	  if(info->theStream->isCout)
	  {
            cout << *(threads[i].getID()) << " " 
		 << threads[i].getDescription() << endl;
	  }
	  else
	  {
	    stream.output << *(threads[i].getID()) << " " 
		 << threads[i].getDescription() << endl;
	  }
      
	}
	info->theStream->mutex_unlock();
	pthread_mutex_unlock(&mutex);
        exitThread(id);
        errorLog->logMessageExit(id);
        pthread_exit(NULL);
    }

    static void* create(void* arg)
    {
      
      struct ThreadInfo2* info = (((struct ThreadInfo2*) arg));
      string name = info->input1;
	
	int id = info->threadID;
        errorLog->logMessageCreate(id);
	
	pthread_mutex_lock(&mutex);
	for(unsigned int i = 0; i < dataBase.size(); ++i)
	{
	  if(dataBase[i].getName() == name)
	  {
	    pthread_mutex_unlock(&mutex);
	    errorLog->logMessageExitFail(id, 
				"when trying to created duplicate Database " 
				+ name + ".");  
	    exitThread(id);
	    pthread_exit(NULL);
	  }
	}
	
        Database temp("./" + name + ".txt", name);
        dataBase.push_back(temp);

	pthread_mutex_unlock(&mutex);
        errorLog->logMessageExit(id);
        exitThread(id);
        pthread_exit(NULL);
    }

    static void* load(void* arg)
    {
      struct ThreadInfo2* info = ((struct ThreadInfo2*) arg);
      string name = info->input1;
        int id = info->threadID;

        errorLog->logMessageCreate(id);
	
	pthread_mutex_lock(&mutex);
	for(unsigned int i = 0; i < dataBase.size(); ++i)
	{
	  if(dataBase[i].getName() == name)
	  {
	    pthread_mutex_unlock(&mutex);
	    errorLog->logMessageExitFail(id, 
	   	 "when asked to load database that is already loaded.");
	    
	    exitThread(id);
            pthread_exit(NULL);
	  }
	}
	 Database db(input[1] + ".txt", name);
   
        if(!db.load())
        {
	    pthread_mutex_unlock(&mutex);
            errorLog->logMessageExitFail(id, 
					 "when it attempts to load database " +
					  name + " which does not exist.");
	    exitThread(id);
            pthread_exit(NULL);
        }

	
        dataBase.push_back(db);
	pthread_mutex_unlock(&mutex);
        errorLog->logMessageExit(id);
	exitThread(id);
        pthread_exit(NULL);
    }

    static void* save(void* arg)
    {
      struct ThreadInfo2* info = (((struct ThreadInfo2*) arg));
        int id = info->threadID;
	string name = info->input1;

	errorLog->logMessageCreate(id);
	
	pthread_mutex_lock(&mutex);
        for(unsigned int i = 0; i < dataBase.size(); ++i)
        {
            if(dataBase[i].getName() == name)
            {
                dataBase[i].save();
		pthread_mutex_unlock(&mutex);
                errorLog->logMessageExit(id);
                exitThread(id);
                pthread_exit(NULL);
            }
        }
	pthread_mutex_unlock(&mutex);
        errorLog->logMessageExitFail(id, "when attemps to save database " + 
				         name + " which does not exist.");
        exitThread(id);
	pthread_exit(NULL);

    }

    static void* insert(void* arg)
    {
        struct ThreadInfo2* info = (((struct ThreadInfo2*) arg));
        int id = info->threadID;
	string keyCode = info->input1;

	errorLog->logMessageCreate(id);

	
	if(keyCode.size() != 6 || keyCode.substr(0,2) > "51" ||
	   keyCode.substr(0,2) < "01")
	{
	      errorLog->logMessageExitFail(id, 
			      "when trying to insert with invalid KeyCode.");
	      exitThread(id);
	      pthread_exit(NULL);
	}
	
	pthread_mutex_lock(&mutex);
        for(unsigned i = 0; i < dataBase.size(); ++i)
	{
	  if(keyCode.substr(0,2) == dataBase[i].getPreCode())
	  {
	    int status = dataBase[i].insert(keyCode);
	    if(status == REPEAT)
	    {
	      pthread_mutex_unlock(&mutex);
	      errorLog->logMessageExitFail(id, "when trying to insert car " +
					       keyCode + " which already " +
					   + "exists.");
	      exitThread(id);
	      pthread_exit(NULL);
	    }
	    else if(status == INVALID)
	    {
	      pthread_mutex_unlock(&mutex);
	      errorLog->logMessageExitFail(id, 
                                "when trying to insert with invalid KeyCode.");
	      exitThread(id);
	      pthread_exit(NULL);
	    }
	    else
	    {
	      pthread_mutex_unlock(&mutex);
	      errorLog->logMessageExit(id);
	      exitThread(id);
	      pthread_exit(NULL);
	    }
	  }
	}

	pthread_mutex_unlock(&mutex);
        errorLog->logMessageExitFail(id, 
	          "when trying to insert into database which does not exist.");
        exitThread(id);
	pthread_exit(NULL);

    }

    static void* del(void* arg)
    {
        struct ThreadInfo2* info = (((struct ThreadInfo2*) arg));
        int id = info->threadID;
	string keyCode = info->input1;

	errorLog->logMessageCreate(id);

	if(keyCode.size() != 6 || keyCode.substr(0,2) > "51" ||
	   keyCode.substr(0,2) < "01")
	{
	      errorLog->logMessageExitFail(id, 
			      "when trying to delete with invalid KeyCode.");
	      exitThread(id);
	      pthread_exit(NULL);
	}

	pthread_mutex_lock(&mutex);
        for(unsigned i = 0; i < dataBase.size(); ++i)
	{
	  if(input[1].substr(0,2) == dataBase[i].getPreCode())
	  {
	    int status = dataBase[i].del(keyCode);
	    if(status == FAILED)
	    {
	      pthread_mutex_unlock(&mutex);
	      errorLog->logMessageExitFail(id, "when trying to delete car " +
					       keyCode + 
					   " which does not exists.");
	      exitThread(id);
	      pthread_exit(NULL);
	    }
	    else if(status == INVALID)
	    {
	      pthread_mutex_unlock(&mutex);
	      errorLog->logMessageExitFail(id, 
                                "when trying to delete with invalid KeyCode.");
	      exitThread(id);
	      pthread_exit(NULL);
	    }
	    else
	    {
	      pthread_mutex_unlock(&mutex);
	      errorLog->logMessageExit(id);
	      exitThread(id);
	      pthread_exit(NULL);
	    }
	  }
	}
	pthread_mutex_unlock(&mutex);
        errorLog->logMessageExitFail(id, 
	          "when trying to delete into database which does not exist.");
        exitThread(id);
	pthread_exit(NULL);

    }

    static void* buy(void* arg)
    {
      
      struct ThreadInfo2* info = (((struct ThreadInfo2*) arg));
      string keyCode = info->input1;
      string num = info->input2;
        int id = info->threadID;
	
	errorLog->logMessageCreate(id);

	if(keyCode.size() != 6 || keyCode.substr(0,2) > "51" ||
	   keyCode.substr(0,2) < "01")
	{
	      errorLog->logMessageExitFail(id, 
			      "when trying to buy with invalid KeyCode.");
	      exitThread(id);
	      pthread_exit(NULL);
	}
	for(unsigned int i = 0; i < num.size(); ++i)
	{
	  char a = num[i];
	  if(a != '0' && a != '1' && a !='2' && a != '3' && a != '4' && 
	     a != '5' && a != '6' && a !='7' && a != '8' && a != '9')
	  {
	    errorLog->logMessageExitFail(id, 
			         "when trying to buy with invalid quantity.");
	    exitThread(id);
	    pthread_exit(NULL);
	  }
	}

	pthread_mutex_lock(&mutex);
	for(unsigned int i = 0; i < dataBase.size(); ++i)
	{
	  if(dataBase[i].getPreCode() == keyCode.substr(0,2))
	  {
	    int status = dataBase[i].buy(keyCode, atoi(num.c_str()));
	    
	    if(status == MYSUCCESS)
	    {
	      pthread_mutex_unlock(&mutex);
	      errorLog->logMessageExit(id);
	      exitThread(id);
	      pthread_exit(NULL);
	    }
	    else if(status == INVALID)
	    {
	      pthread_mutex_unlock(&mutex);
	         errorLog->logMessageExitFail(id, 
			      "when trying to buy with invalid KeyCode.");
	        exitThread(id);
	        pthread_exit(NULL);
	    }
	    else if(status == FAILED)
	    {
	      pthread_mutex_unlock(&mutex);
	      errorLog->logMessageExitFail(id,
			     "when trying to buy a car that does not exists.");
	    
	      exitThread(id);
	      pthread_exit(NULL);
	    }
	  }
	}

	pthread_mutex_unlock(&mutex);
	errorLog->logMessageExitFail(id,
		   "when trying to buy from a database that does not exists.");
	    
	      exitThread(id);
	      pthread_exit(NULL);

    }

    static void* sell(void* arg)
    {
      struct ThreadInfo2* info = (((struct ThreadInfo2*) arg));
      string keyCode = info->input1;
      string num = info->input2;
        int id = info->threadID;

	errorLog->logMessageCreate(id);

	
	if(keyCode.size() != 6 || keyCode.substr(0,2) > "51" ||
	   keyCode.substr(0,2) < "01")
	{
	      errorLog->logMessageExitFail(id, 
			      "when trying to sell with invalid KeyCode.");
	      exitThread(id);
	      pthread_exit(NULL);
	}
	for(unsigned int i = 0; i < num.size(); ++i)
	{
	  char a = num[i];
	  if(a != '0' && a != '1' && a !='2' && a != '3' && a != '4' && 
	     a != '5' && a != '6' && a !='7' && a != '8' && a != '9')
	  {
	    errorLog->logMessageExitFail(id, 
			         "when trying to sell with invalid quantity.");
	    exitThread(id);
	    pthread_exit(NULL);
	  }
	}

	pthread_mutex_lock(&mutex);
	for(unsigned int i = 0; i < dataBase.size(); ++i)
	{
	  if(dataBase[i].getPreCode() == keyCode.substr(0,2))
	  {
	    int status = dataBase[i].sell(keyCode, atoi(num.c_str()));
	    
	    if(status == MYSUCCESS)
	    {
	      pthread_mutex_unlock(&mutex);
	      errorLog->logMessageExit(id);
	      exitThread(id);
	      pthread_exit(NULL);
	    }
	    else if(status == WARNING)
	    {
	      pthread_mutex_unlock(&mutex);
	      errorLog->logMessageWarning("The " + dataBase[i].getState() + 
					  " " + dataBase[i].getManu(i) + " " +
					  dataBase[i].getBrand(i) +
					  " is out of storage.");

	      errorLog->logMessageExit(id);
	      exitThread(id);
	       pthread_exit(NULL);
	      
	    }
	    else if(status == INVALID)
	    {
	      pthread_mutex_unlock(&mutex);
	         errorLog->logMessageExitFail(id, 
			      "when trying to buy with invalid KeyCode.");
	        exitThread(id);
	        pthread_exit(NULL);
	    }
	    else if(status == FAILED)
	    {
	      pthread_mutex_unlock(&mutex);
	      errorLog->logMessageExitFail(id,
			     "when trying to buy a car that does not exists.");
	    
	      exitThread(id);
	      pthread_exit(NULL);
	    }
	  }
	}
	
	pthread_mutex_unlock(&mutex);
	errorLog->logMessageExitFail(id,
		   "when trying to buy from a database that does not exists.");
	    
	      exitThread(id);
	      pthread_exit(NULL);

    }

    static void* printi(void* arg)
    {
      
      struct ThreadInfo2* info = (((struct ThreadInfo2*) arg));
      string name = info->input1;
        int id = info->threadID;

	errorLog->logMessageCreate(id);
     
      pthread_mutex_lock(&mutex);
      
      for(unsigned int i = 0; i < dataBase.size(); ++i)
      {
	if(dataBase[i].getName() == name)
	{
	  info->theStream->mutex_lock();
	  if(info->theStream->isCout)
	    dataBase[i].print(true, NULL);
	  else
	    dataBase[i].print(false, &(info->theStream->output));
	  info->theStream->mutex_unlock();
	  pthread_mutex_unlock(&mutex);
	  exitThread(id);
	  pthread_exit(NULL);
	}
      }
      
      pthread_mutex_unlock(&mutex);
      errorLog->logMessageExitFail(id, 
		        "when trying to print database that does not exist.");
      exitThread(id);
      pthread_exit(NULL);
    }

    static void* printo(void* arg)
    {
      struct ThreadInfo2* info = (((struct ThreadInfo2*) arg));
      string keyWord = info->input1;
        int id = info->threadID;

	errorLog->logMessageCreate(id);

      for(unsigned int i = 0; i < keyWord.size(); ++i)
	{
	  char a = keyWord[i];
	  if(a != '0' && a != '1' && a !='2' && a != '3' && a != '4' && 
	     a != '5' && a != '6' && a !='7' && a != '8' && a != '9')
	  {
	    errorLog->logMessageExitFail(id, 
			      "when trying to print with invalid key word" +
			      keyWord + ".");
	    exitThread(id);
	    pthread_exit(NULL);
	  }
	}
      
      if(keyWord.size() % 2 != 0)
      {
	errorLog->logMessageExitFail(id, 
			      "when trying to print with invalid key word" +
			       keyWord + ".");
	    exitThread(id);
	    pthread_exit(NULL);
      }
      
      pthread_mutex_lock(&mutex);
      for(unsigned int i = 0; i < dataBase.size(); ++i)
      {
	if(dataBase[i].getPreCode() == keyWord.substr(0,2))
	{
	  int status;
	  info->theStream->mutex_lock();
	  if(info->theStream->isCout)
	    status = dataBase[i].printo(keyWord, true, NULL);
	  else
	    status = dataBase[i].printo(keyWord, false, 
					&(info->theStream->output));
	  info->theStream->mutex_unlock();
	  pthread_mutex_unlock(&mutex);
	  if(status == FAILED)
	  {
	    errorLog->logMessageExitFail(id, "when trying to print all cars in database that match key work " + keyWord + ".");
	  }
	  errorLog->logMessageExit(id);
	  exitThread(id);
	  pthread_exit(NULL);
	}
      }

      pthread_mutex_unlock(&mutex);
       errorLog->logMessageExitFail(id, 
		        "when trying to print database that does not exist.");

      exitThread(id);
      pthread_exit(NULL);
    }


    static void* srun(void* arg)
    {
      struct ThreadInfo2 info = *(((struct ThreadInfo2*) arg));
      string inFileName = info.input1;
      string outFileName = info.input2;
      
      int id = info.threadID;
      errorLog->logMessageCreate(id);

      ifstream infile;
      infile.open(inFileName.c_str());
      
      if(!infile.is_open())
      {
	errorLog->logMessageExitFail(id, 
			      "when trying to use an input file that does not exist.");
	exitThread(id);
	pthread_exit(NULL);
      }

      ofstream outfile;
      outfile.open(outFileName.c_str());
      
      string command;
      
      while(!infile.eof())
      {
	infile >> command;
	if(infile.eof())
	  break;
      
	if(command == "list")
	  {
	    pthread_mutex_lock(&mutex);
	    for(unsigned int i = 0; i < threads.size(); ++i)
	      {
		outfile << *(threads[i].getID()) << " " 
		     << threads[i].getDescription() << endl;
	      }
	    
	    pthread_mutex_unlock(&mutex);       
	    
	  }
	else if(command == "create")
	  {
	    bool stop = false;
	    string name;
	    infile >> name;
	    pthread_mutex_lock(&mutex);
	    for(unsigned int i = 0; i < dataBase.size(); ++i)
	      {
		if(dataBase[i].getName() == name)
		  {
		    pthread_mutex_unlock(&mutex);
		    errorLog->logMessageExitFail(id, 
				 "when trying to created duplicate Database " 
						 + name + "."); 
		    stop = true;
		    break;
		  }
	      }
	    if(stop)
	      continue;
	    
	    Database temp("./" + name + ".txt", name);
	    dataBase.push_back(temp);
	    
	    pthread_mutex_unlock(&mutex);
	  }
	else if(command == "load")
	  {
	    string name;
	    infile >> name;
	    bool stop = false;
	    pthread_mutex_lock(&mutex);
	    for(unsigned int i = 0; i < dataBase.size(); ++i)
	      {
		if(dataBase[i].getName() == name)
		  {
		    pthread_mutex_unlock(&mutex);
		    errorLog->logMessageExitFail(id, 
						 "when asked to load database that is already loaded.");
		    stop = true;
		    break;
		  }
	      }
	    if(stop)
	      continue;
	    Database db(input[1] + ".txt", name);
	    
	    if(!db.load())
	      {
		pthread_mutex_unlock(&mutex);
		errorLog->logMessageExitFail(id, 
					     "when it attempts to load database " +
					     name + " which does not exist.");
		stop = true;
	      }
	    
	    if(stop)
	      continue;
	    
	    dataBase.push_back(db);
	    pthread_mutex_unlock(&mutex);
	  }
	else if(command == "save")
	  {
	    string name;
	    infile >> name;
	    
	    bool stop = false;

	    pthread_mutex_lock(&mutex);
	    for(unsigned int i = 0; i < dataBase.size(); ++i)
	      {
		if(dataBase[i].getName() == name)
		  {
		    dataBase[i].save();
		    pthread_mutex_unlock(&mutex);
		    stop = true;
		    break;
		  }
	      }
	    if(stop)
	      continue;
	    pthread_mutex_unlock(&mutex);
	  }
	else if(command == "insert")
	  {
	    string keyCode;
	    infile >> keyCode;
	    
	    
	    if(keyCode.size() != 6 || keyCode.substr(0,2) > "51" ||
	       keyCode.substr(0,2) < "01")
	      {
		errorLog->logMessageExitFail(id, 
					     "when trying to insert with invalid KeyCode.");
		continue;
	      }
	    
	    pthread_mutex_lock(&mutex);
	    bool stop = false;
	    for(unsigned i = 0; i < dataBase.size(); ++i)
	      {
		if(keyCode.substr(0,2) == dataBase[i].getPreCode())
		  {
		    int status = dataBase[i].insert(keyCode);
		    if(status == REPEAT)
		      {
			pthread_mutex_unlock(&mutex);
			errorLog->logMessageExitFail(id, "when trying to insert car " +
						     keyCode + " which already " +
						     + "exists.");
			stop = true;
			break;
		      }
		    else if(status == INVALID)
		      {
			pthread_mutex_unlock(&mutex);
			errorLog->logMessageExitFail(id, 
						     "when trying to insert with invalid KeyCode.");
			stop = true;
			break;
		      }
		    else
		      {
			pthread_mutex_unlock(&mutex);
			errorLog->logMessageExit(id);
			stop = true;
			break;
		      }
		  }
	      }
	    
	    if(stop)
	      continue;

	    pthread_mutex_unlock(&mutex);
	    errorLog->logMessageExitFail(id, 
					 "when trying to insert into database which does not exist.");
	    
	  }
	else if(command == "delete")
	  {
	    string keyCode;
	    infile >> keyCode;

	    if(keyCode.size() != 6 || keyCode.substr(0,2) > "51" ||
	       keyCode.substr(0,2) < "01")
	      {
	      errorLog->logMessageExitFail(id, 
					   "when trying to delete with invalid KeyCode.");
	      continue;
	      }
	    
	    pthread_mutex_lock(&mutex);
	    bool stop = false;
	    for(unsigned i = 0; i < dataBase.size(); ++i)
	      {
		if(input[1].substr(0,2) == dataBase[i].getPreCode())
		  {
		    int status = dataBase[i].del(keyCode);
		    if(status == FAILED)
		      {
			pthread_mutex_unlock(&mutex);
			errorLog->logMessageExitFail(id, "when trying to delete car " +
						     input[1] + 
						     " which does not exists.");
			stop = true;
			break;
		      }
		    else if(status == INVALID)
		      {
			pthread_mutex_unlock(&mutex);
			errorLog->logMessageExitFail(id, 
						     "when trying to delete with invalid KeyCode.");
			stop = true;
			break;
		      }
		    else
		      {
			pthread_mutex_unlock(&mutex);
			errorLog->logMessageExit(id);
			stop = true;
			break;
		      }
		  }
	      }
	    if(stop)
	      continue;
	    pthread_mutex_unlock(&mutex);
	    errorLog->logMessageExitFail(id, 
					 "when trying to delete into database which does not exist.");
	    
	  }
	else if(command == "buy")
	  {
	    string keyCode;
	    string num;
	    infile >> keyCode;
	    infile >> num;
     
	    if(keyCode.size() != 6 || keyCode.substr(0,2) > "51" ||
	       keyCode.substr(0,2) < "01")
	      {
		errorLog->logMessageExitFail(id, 
				 "when trying to buy with invalid KeyCode.");
		continue;
	      }
	    bool stop = false;
	    for(unsigned int i = 0; i < num.size(); ++i)
	      {
		char a = num[i];
		if(a != '0' && a != '1' && a !='2' && a != '3' && a != '4' && 
		   a != '5' && a != '6' && a !='7' && a != '8' && a != '9')
		  {
		    errorLog->logMessageExitFail(id, 
						 "when trying to buy with invalid quantity.");
		    stop = true;
		    break;
		  }
	      }
	    if(stop)
	      continue;
	    
	    pthread_mutex_lock(&mutex);
	    for(unsigned int i = 0; i < dataBase.size(); ++i)
	      {
		if(dataBase[i].getPreCode() == keyCode.substr(0,2))
		  {
		    int status = dataBase[i].buy(keyCode, atoi(num.c_str()));
		    
		    if(status == MYSUCCESS)
		      {
			pthread_mutex_unlock(&mutex);
			errorLog->logMessageExit(id);
			stop = true;
			break;
		      }
		    else if(status == INVALID)
		      {
			pthread_mutex_unlock(&mutex);
			errorLog->logMessageExitFail(id, 
			       "when trying to buy with invalid KeyCode.");
			stop = true;
			break;
		      }
		    else if(status == FAILED)
		      {
			pthread_mutex_unlock(&mutex);
			errorLog->logMessageExitFail(id,
			     "when trying to buy a car that does not exists.");
			
			stop = true;
			break;
		      }
		  }
	      }
	    if(stop)
	      continue;
	    
	    pthread_mutex_unlock(&mutex);
	    errorLog->logMessageExitFail(id,
		 "when trying to buy from a database that does not exists.");
	    
	  }
	else if(command == "sell")
	  {
	    
	    string keyCode;
	    infile >> keyCode;
	    string num;
	    infile >> num;	    
	    
	    if(keyCode.size() != 6 || keyCode.substr(0,2) > "51" ||
	       keyCode.substr(0,2) < "01")
	      {
		errorLog->logMessageExitFail(id, 
					     "when trying to sell with invalid KeyCode.");
		continue;
	      }
	    bool stop = false;
	    for(unsigned int i = 0; i < num.size(); ++i)
	      {
		char a = num[i];
		if(a != '0' && a != '1' && a !='2' && a != '3' && a != '4' && 
		   a != '5' && a != '6' && a !='7' && a != '8' && a != '9')
		  {
		    errorLog->logMessageExitFail(id, 
						 "when trying to sell with invalid quantity.");
		    stop = true;
		    break;
		  }
	      }
	    if(stop)
	      continue;
	    
	    pthread_mutex_lock(&mutex);
	    for(unsigned int i = 0; i < dataBase.size(); ++i)
	      {
		if(dataBase[i].getPreCode() == keyCode.substr(0,2))
		  {
		    int status = dataBase[i].sell(keyCode, atoi(num.c_str()));
		    
		    if(status == MYSUCCESS)
		      {
			pthread_mutex_unlock(&mutex);
			stop = true;
			break;
		      }
		    else if(status == WARNING)
		      {
			pthread_mutex_unlock(&mutex);
			errorLog->logMessageWarning(
				       "The " + dataBase[i].getState() + 
				       " " + dataBase[i].getManu(i) + " " +
				       dataBase[i].getBrand(i) +
				       " is out of storage.");
			
			stop = true;
			break;
			
		      }
		    else if(status == INVALID)
		      {
			pthread_mutex_unlock(&mutex);
			errorLog->logMessageExitFail(id, 
						     "when trying to sell with invalid KeyCode.");
			stop = true;
			break;
		      }
		    else if(status == FAILED)
		      {
			pthread_mutex_unlock(&mutex);
			errorLog->logMessageExitFail(id,
						     "when trying to sell a car that does not exists.");
			
			stop = true;
			break;
		      }
		  }
	      }
	    if(stop)
	      continue;
	    
	    pthread_mutex_unlock(&mutex);
	    errorLog->logMessageExitFail(id,
					 "when trying to buy from a database that does not exists.");
	    
	  }
	else if(command == "printi")
	  {
	    string name;
	    infile >> name;
	    
	    pthread_mutex_lock(&mutex);
	    bool stop = false;
	    for(unsigned int i = 0; i < dataBase.size(); ++i)
	      {
		if(dataBase[i].getName() == name)
		  {
		    dataBase[i].print(false , &outfile);
		    pthread_mutex_unlock(&mutex);
		    stop = true;
		    continue;
		  }
	      }
	    
	    if(stop)
	      continue;
	    pthread_mutex_unlock(&mutex);
	    errorLog->logMessageExitFail(id, 
			 "when trying to print database that does not exist.");
	  
	  }
	else if(command == "printo")
	  {
	    string keyWord;
	    infile >> keyWord;
	    
	    bool stop = false;
	    for(unsigned int i = 0; i < keyWord.size(); ++i)
	      {
		char a = keyWord[i];
		if(a != '0' && a != '1' && a !='2' && a != '3' && a != '4' && 
		   a != '5' && a != '6' && a !='7' && a != '8' && a != '9')
		  {
		    errorLog->logMessageExitFail(id, 
			       "when trying to print with invalid key word" +
						 keyWord + ".");
		    stop = true;
		    break;
		  }
	      }
	    if(stop)
	      continue;
	    
	    if(keyWord.size() % 2 != 0)
	      {
		errorLog->logMessageExitFail(id, 
					     "when trying to print with invalid key word" +
					     keyWord + ".");
		continue;
	      }
	    
	    pthread_mutex_lock(&mutex);
	    for(unsigned int i = 0; i < dataBase.size(); ++i)
	      {
		if(dataBase[i].getPreCode() == keyWord.substr(0,2))
		  {
		    int status = dataBase[i].printo(keyWord, false, &outfile);
		    pthread_mutex_unlock(&mutex);
		    if(status == FAILED)
		      {
			errorLog->logMessageExitFail(id, "when trying to print all cars in database that match key work " + keyWord + ".");
		      }
		    stop = true;
		    break;
		  }
	      }
	    if(stop)
	      continue;
	    
	    pthread_mutex_unlock(&mutex);
	    errorLog->logMessageExitFail(id, 
					 "when trying to print database that does not exist.");
	    
	  }
	else if(command == "srun")
	  {
	    errorLog->logMessage("Error: When trying to run a srun in a srun.");
	  }
	else if(command == "prun")
	  {
	    errorLog->logMessage("Error: When trying to run a prun in a srun.");
	  }
	else if(command == "quit")
	  {
	    errorLog->logMessage("Error: When trying to run a prun in a srun.");
	  }
      }
      exitThread(id);
      pthread_exit(NULL);
    }

    static void* prun(void* arg)
    {
      struct ThreadInfo2 info = (*((struct ThreadInfo2*) arg));
      string inFileName = info.input1;
      string outFileName = info.input2;
      
      int id = info.threadID;
      errorLog->logMessageCreate(id);
   
      ifstream infile;
      infile.open(inFileName.c_str());
      
      if(!infile.is_open())
      {
	errorLog->logMessageExitFail(id, 
		      "when trying to use an input file that does not exist.");
	exitThread(id);
	pthread_exit(NULL);
      }
     
      
      if(stream.output.is_open())
	stream.close();
     
          
      stream.isCout = false;
     
      stream.filename = inFileName;
      
      stream.open();
      
      string command;
      
      while(!infile.eof())
      {
	infile >> command;
	if(infile.eof())
	  break;

	if(command == "list")
	{
	   ThreadObj temp;
	   pthread_mutex_lock(&mutex);
	   threads.push_back(temp);
	   threads[threads.size() - 1].setDescription(
			           "Outputing a list of all running Threads");
	   threads[threads.size() - 1].setID(threadNum++);
	   struct ThreadInfo2* info2 = new struct ThreadInfo2;
	   info2->theStream = &stream;
	   info2->threadID = threadNum - 1;
	   info2->infile = &infile;
	   pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			  list, (void *) 
			  (info2));
	   pthread_mutex_unlock(&mutex);
	}
	else if(command == "create")
	{
	  string state;
	  infile >> state;
	  ThreadObj temp;
	  pthread_mutex_lock(&mutex);
	  threads.push_back(temp);
	  threads[threads.size() - 1].setDescription("Creating database "
						     + input[1]);
	  threads[threads.size() - 1].setID(threadNum++);
	  struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &stream;
		info->input1 = state;
	  pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			 create, (void *) 
			 (info));
	  pthread_mutex_unlock(&mutex);
	}
	else if(command == "load")
	{
	  string state;
	  infile >> state;
	  ThreadObj temp;
	  pthread_mutex_lock(&mutex);
	  threads.push_back(temp);
	  threads[threads.size() - 1].setDescription("Loading database " 
						     + input[1]);
	  threads[threads.size() - 1].setID(threadNum++);
	  struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &stream;
		info->input1 = state;
	  pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			 load, (void *) 
			 (info));
	pthread_mutex_unlock(&mutex);
	}
	else if(command == "save")
	{
	  string state;
	  infile >> state;
	  ThreadObj temp;
	  pthread_mutex_lock(&mutex);
	  threads.push_back(temp);
	  threads[threads.size() - 1].setDescription("Saving database " +
						     input[1]);
	  threads[threads.size() - 1].setID(threadNum++);
	  struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &stream;
		info->input1 = state;
	  pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			 save, (void *) 
			 (info));
	  pthread_mutex_unlock(&mutex);
	}
	else if(command == "insert")
	{
	  string code;
	  infile >> code;
	  ThreadObj temp;
	  pthread_mutex_lock(&mutex);
	  threads.push_back(temp);
	  threads[threads.size() - 1].setDescription(
					    "Inserting KeyCode: " + input[1]);
	  threads[threads.size() - 1].setID(threadNum++);
	  struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &stream;
		info->input1 = code;
	  pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			 insert, (void *) 
			 (info));
	  pthread_mutex_unlock(&mutex);
	}
	else if(command == "delete")
	{
	  string code;
	  infile >> code;
	  
	  ThreadObj temp;
	  pthread_mutex_lock(&mutex);
	  threads.push_back(temp);
	  threads[threads.size() - 1].setDescription(
					     "Deleting Keycode: " + input[1]);
	  threads[threads.size() - 1].setID(threadNum++);
	  struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &stream;
		info->input1 = code;
	  pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			 del, (void *) 
			 (info));
	  pthread_mutex_unlock(&mutex);
	}
	else if(command == "buy")
	{
	  string code;
	  string num;
	  infile >> code;
	  infile >> num;
	  ThreadObj temp;
	  pthread_mutex_lock(&mutex);
	  threads.push_back(temp);
	  threads[threads.size() - 1].setDescription(
      	     "Buying amount: " + input[2] +
					     " of keyCode: " + input[1] + ".");
	  threads[threads.size() - 1].setID(threadNum++);
	  struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &stream;
		info->input1 = code;
		info->input2 = num;
	  pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			 buy, (void *) 
		       (info));
	  pthread_mutex_unlock(&mutex);
	}
	else if(command == "sell")
	{
	  string code;
	  string num;
	  infile >> code;
	  infile >> num;
	  ThreadObj temp;
	  pthread_mutex_lock(&mutex);
	  threads.push_back(temp);
	  threads[threads.size() - 1].setDescription(
	       "Buying amount: " + input[2] +" of keyCode: " + input[1] + ".");
	  threads[threads.size() - 1].setID(threadNum++);
	  struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &stream;
		info->input1 = code;
		info->input2 = num;
	  pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			 sell, (void *) 
			 (info));
	  pthread_mutex_unlock(&mutex);
	}
	else if(command == "printi")
	{
	  string state;
	  infile >> state;
	  ThreadObj temp;
	  pthread_mutex_lock(&mutex);
	  threads.push_back(temp);
	  threads[threads.size() - 1].setDescription(
     		     "Printing entries in " + input[1] +  ".");
	  threads[threads.size() - 1].setID(threadNum++);
	  struct ThreadInfo2* info = new struct ThreadInfo2;
	  info->threadID = threadNum - 1;
	  info->theStream = &stream;
	  info->input1 = state;
	  pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			 printi, (void *) 
			 (info));
	  pthread_mutex_unlock(&mutex);
	}
	else if(command == "printo")
	{
	  string code;
	  infile >> code;
	  ThreadObj temp;
	  pthread_mutex_lock(&mutex);
	  threads.push_back(temp);
	  threads[threads.size() - 1].setDescription(
				    "Printing entries that match " + 
						     input[1] + ".");
	  threads[threads.size() - 1].setID(threadNum++);
	  struct ThreadInfo2* info = new struct ThreadInfo2;
	  info->threadID = threadNum - 1;
	  info->theStream = &stream;
	  info->input1 = code;
	  pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			 printo, (void *) 
			 (info));
	  pthread_mutex_unlock(&mutex);
	}
	else if(command == "kill")
	{
	  string name;
	  infile >> name;
	  ThreadObj temp;
	  pthread_mutex_lock(&mutex);
	  threads.push_back(temp);
	  threads[threads.size() - 1].setDescription(
	       "Killing Thread: " + input[1] + ".");
	  threads[threads.size() - 1].setID(threadNum++);
	  struct ThreadInfo2* info = new struct ThreadInfo2;
	  info->threadID = threadNum - 1;
	  info->theStream = &stream;
	  info->input1 = name;
	  pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			 kill, (void *) 
			 (&info));
	   pthread_mutex_unlock(&mutex);
	}
	else if(command == "srun")
	{
	  errorLog->logMessage("Error: When trying to run a srun in a prun.");
	}
	else if(command == "prun")
	{
	  errorLog->logMessage("Error: When trying to run a prun in a prun.");
	}
      }
      infile.close();
      exitThread(id);
      pthread_exit(NULL);
    }

    static void* ThreadMgrThread(void* arg)
    {
      int id = *((int*)arg);
      id = 5;
      char** argv2 = argv;
     
      int rc = MPI_Init(&argc, &argv2);
    
      if (rc != MPI_SUCCESS)
	{
	  cout << "Error starting MPI program. Terminating now...." << endl;
	  MPI_Abort(MPI_COMM_WORLD, rc);
	}
     
        errorLog->logMessageCreate(0);
        
	
	//	int rank;
	//	int position = 0;
	//	char buffer[100];
	char data[100];

	MPI_Status Stat;

	OutStream couter;

	couter.init();

        while(true)
        {
	 
	  //RECEIVE A MESSAGE!!!!
	  MPI_Recv(data, 100, MPI_CHAR, 0, MPI_ANY_TAG, 
		   MPI_COMM_WORLD, &Stat);
	  input[0] = data;
	 
	  MPI_Recv(data, 100, MPI_CHAR, 0, MPI_ANY_TAG, 
		   MPI_COMM_WORLD, &Stat);
	  input[1] = data;
	  
	  MPI_Recv(data, 100, MPI_CHAR, 0, MPI_ANY_TAG, 
		   MPI_COMM_WORLD, &Stat);
	  input[2] = data;
	 
	  //cout << buffer << endl;
	  //THEN GET EVERYTHING OUT FROM THE PACK

	  
	  /*
	  MPI_Unpack(buffer, 310, &position, data, 100, MPI_CHAR,

	             MPI_COMM_WORLD);
	  cout << "1" << endl;
	  input[0] = data;
	  cout << input[0] << endl;
	  //MPI_Unpack(buffer, 310, &position, data, 100, MPI_CHAR,
	  //	     MPI_COMM_WORLD);
	  //input[1] = data;
	  //MPI_Unpack(buffer, 310, &position, data, 100, MPI_CHAR,
	  //	     MPI_COMM_WORLD);
	  //input[2] = data;
	  //MPI_Unpack(buffer, 310, &position, &rank, 10, MPI_INT, 
	  //     MPI_COMM_WORLD);
	  */

	  
	 
            if(input[0] == "list")
            {
                ThreadObj temp;
		pthread_mutex_lock(&mutex);
                threads.push_back(temp);
                threads[threads.size() - 1].setDescription(
				    "Outputing a list of all running Threads");
                threads[threads.size() - 1].setID(threadNum++);
                struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &couter;
		pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			       list, (void *) 
			             (info));
		 pthread_mutex_unlock(&mutex);
	    }
            if(input[0] == "quit")
            {
	      pthread_mutex_lock(&mutex);
	      errorLog->logMessageExit(0);
	      while(threads.size() > 1)
	      {
		pthread_cancel(*(threads[threads.size() - 1].getThread()));
		threads.pop_back();
	      }
	      pthread_mutex_unlock(&mutex);
	      break;

            }
            if(input[0] == "create")
            {
                ThreadObj temp;
		pthread_mutex_lock(&mutex);
                threads.push_back(temp);
                threads[threads.size() - 1].setDescription("Creating database "
							   + input[1]);
                threads[threads.size() - 1].setID(threadNum++);
		struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &couter;
		info->input1 = input[1];
                pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			       create, (void *) 
			               (&info));
		 pthread_mutex_unlock(&mutex);
	    }
            if(input[0] == "load")
	    {
                ThreadObj temp;
		pthread_mutex_lock(&mutex);
                threads.push_back(temp);
                threads[threads.size() - 1].setDescription("Loading database " 
							   + input[1]);
                threads[threads.size() - 1].setID(threadNum++);
		struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &couter;
		info->input1 = input[1];
                pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			       load, (void *) 
			             (info));
		 pthread_mutex_unlock(&mutex);
	    }
            if(input[0] == "save")
            {
	     
                ThreadObj temp;
		pthread_mutex_lock(&mutex);
                threads.push_back(temp);
                threads[threads.size() - 1].setDescription("Saving database " +
							   input[1]);
                threads[threads.size() - 1].setID(threadNum++);
	        struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &couter;
		info->input1 = input[1];
                pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			       save, (void *) 
			             (info));
		 pthread_mutex_unlock(&mutex);
	    }
            if(input[0] == "insert")
            {
                ThreadObj temp;
		pthread_mutex_lock(&mutex);
                threads.push_back(temp);
                threads[threads.size() - 1].setDescription(
					    "Inserting KeyCode: " + input[1]);
                threads[threads.size() - 1].setID(threadNum++);
	        struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &couter;
		info->input1 = input[1];
                pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			       insert, (void *) 
			               (info));
		pthread_mutex_unlock(&mutex);
	    }
            if(input[0] == "delete")
            {
                ThreadObj temp;
		pthread_mutex_lock(&mutex);
		threads.push_back(temp);
                threads[threads.size() - 1].setDescription(
					    "Deleting Keycode: " + input[1]);
                threads[threads.size() - 1].setID(threadNum++);
		struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &couter;
		info->input1 = input[1];
                pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			       del, (void *) 
			               (info));
		 pthread_mutex_unlock(&mutex);
            }
            if(input[0] == "buy")
            {
	         ThreadObj temp;
		 pthread_mutex_lock(&mutex);
                threads.push_back(temp);
                threads[threads.size() - 1].setDescription(
					    "Buying amount: " + input[2] +
					   " of keyCode: " + input[1] + ".");
                threads[threads.size() - 1].setID(threadNum++);
	        struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &couter;
		info->input1 = input[1];
		info->input2 = input[2];
                pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			       buy, (void *) 
			               (info));

		 pthread_mutex_unlock(&mutex);
	    }
            if(input[0] == "sell")
            {
	      ThreadObj temp;
	      pthread_mutex_lock(&mutex);
                threads.push_back(temp);
                threads[threads.size() - 1].setDescription(
					    "Buying amount: " + input[2] +
					   " of keyCode: " + input[1] + ".");
                threads[threads.size() - 1].setID(threadNum++);
		struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &couter;
		info->input1 = input[1];
		info->input2 = input[2];
                pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			       sell, (void *) 
			               (info));
		 pthread_mutex_unlock(&mutex);
            }
            if(input[0] == "printi")
            {
               ThreadObj temp;
	        pthread_mutex_lock(&mutex);
                threads.push_back(temp);
                threads[threads.size() - 1].setDescription(
					    "Printing entries in " + input[1]
					    + ".");
                threads[threads.size() - 1].setID(threadNum++);
	        struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &couter;
		info->input1 = input[1];
                pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			       printi, (void *) 
			               (info));

		 pthread_mutex_unlock(&mutex);
	    }
            if(input[0] == "printo")
            {
               ThreadObj temp;
	        pthread_mutex_lock(&mutex);
                threads.push_back(temp);
                threads[threads.size() - 1].setDescription(
					    "Printing entries that match " + 
					    input[1] + ".");
                threads[threads.size() - 1].setID(threadNum++);
		struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &couter;
		info->input1 = input[1];
                pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			       printo, (void *) 
			               (info));

		 pthread_mutex_unlock(&mutex);
	    }
	    if(input[0] == "srun")
	    {
	      ThreadObj temp;
	       pthread_mutex_lock(&mutex);
                threads.push_back(temp);
                threads[threads.size() - 1].setDescription(
				  "Sequentially running commands from file " + 
					    input[1] + ".");
                threads[threads.size() - 1].setID(threadNum++);
		struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &couter;
		info->input1 = input[1];
		info->input2 = input[2];
                pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			       srun, (void *) 
			               (info));
	      
		 pthread_mutex_unlock(&mutex);
	    }
	    if(input[0] == "prun")
	    {
	       ThreadObj temp;
	        pthread_mutex_lock(&mutex);
                threads.push_back(temp);
                threads[threads.size() - 1].setDescription(
				    "Parallel running commands from file " + 
					    input[1] + ".");
                threads[threads.size() - 1].setID(threadNum++);
		struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &couter;
		info->input1 = input[1];
		info->input2 = input[2];
                pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			       prun, (void *) 
		               (info));
		 pthread_mutex_unlock(&mutex);
	    }
	    if(input[0] == "kill")
	    {
	      ThreadObj temp;
	       pthread_mutex_lock(&mutex);
              threads.push_back(temp);
              threads[threads.size() - 1].setDescription(
			    "Parallel running commands from file " + 
				    input[1] + ".");
	      struct ThreadInfo2* info = new struct ThreadInfo2;
		info->threadID = threadNum - 1;
		info->theStream = &couter;
		info->input1 = input[1];
              threads[threads.size() - 1].setID(threadNum++);
	      pthread_create(threads[threads.size() - 1].getThread(), NULL, 
			       kill, (void *) 
			     (info));
	       pthread_mutex_unlock(&mutex);
	    }
        }
        //errorLog->logMessageExit(0);
	MPI_Finalize();
	pthread_exit(NULL);
    }

  private:
    pthread_t theThread;
    static pthread_cond_t condition;
    static pthread_mutex_t mutex;
    static vector <string> input;
    static vector <ThreadObj> threads;
    static vector <Database> dataBase;
    static unsigned int threadNum;
    static Log* errorLog;
    static int argc;
    static char** argv;
    static OutStream stream;

};


#endif
